package clases;

import java.io.FileNotFoundException;

public class Individuo {

  private EvalTree tree;
  private double aptitude;
  private double relativeAptitude;
  private double accumulatedAptitude;
  private String solution;
  private int solcant;
  private String output;

  public Individuo(int solcant) {
    this.tree = new EvalTree(solcant);
    this.aptitude = -1;
    this.relativeAptitude = 0;
    this.accumulatedAptitude = 0;
    this.solution = null;
    this.solcant = solcant;
    this.output = null;
  }

  public Individuo(String sol, int sollength) {
    this.tree = new EvalTree(solcant);
    this.aptitude = -1;
    this.relativeAptitude = 0;
    this.accumulatedAptitude = 0;
    this.solution = new String(sol);
    this.solcant = this.solution.length();
    this.output = null;
  }

  public void randomIndividuo(int maxHeight) {
    this.tree.newRandomTree(maxHeight,this.solcant);
  }

  public double getAptitude() throws Exception {
    if (this.aptitude == -1) {
      calculateAptitude();
    }
    return this.aptitude;
  }
  
  public String getOutput() throws Exception{
    if(this.output==null){
      calculateAptitude();
    }
    return this.output;
  }

  private void calculateAptitude() throws Exception {
    this.aptitude = 0;

    this.output = this.tree.evalAllTreeInputs();

    for (int j = 0; j < this.solcant; j++) {
      if (this.output.charAt(j) == this.solution.charAt(j)) {
        /*
        if(this.output.charAt(j) == '1'){
          this.aptitude += 2; // si coincide el bit, sumo 2
        }
        else{
          this.aptitude += 1; // si coincide el bit, sumo 1
        }*/
        this.aptitude += 1;
      } 
    }
  }

  public Individuo clone() {
    Individuo resp = new Individuo(this.solution, this.solcant);

    resp.aptitude = this.aptitude;
    resp.accumulatedAptitude = this.accumulatedAptitude;
    resp.relativeAptitude = this.relativeAptitude;
    resp.tree = this.tree.clone();
    resp.solution = new String(this.solution);
    return resp;
  }

  public void setRelativeAptitude(double relative) {
    this.relativeAptitude = relative;
  }

  public void setAccumulatedAptitude(double acum) {
    this.accumulatedAptitude = acum;
  }

  public void reproduction(Individuo individuo) {
    this.tree.reproduceTree(individuo.tree);
    // mutar
    this.tree.mutate();
    individuo.tree.mutate();
    // marcar la aptitud como "no calculada"
    this.aptitude = -1;
    this.output = null;
    individuo.aptitude = -1;
    individuo.output = null;
    // TODO probar si: los clones que se hacen antes de llamar a reproduccion
    // tienen que setearse en -1 la aptitud
  }

  public void printOutput() throws Exception {
    System.out.println(this.tree.evalAllTreeInputs());
  }

  public double getRelativeAptitude() {
    return relativeAptitude;
  }

  public double getAccumulatedAptitude() {
    return accumulatedAptitude;
  }

  public void setAptitude(double aptitude) {
    this.aptitude = aptitude;
  }
  
  public void generateDOT(String path) throws FileNotFoundException{
    this.tree.generateDOT(path);
  }

}
